package com.george.common.exception;

import com.alibaba.fastjson.JSONException;
import com.george.common.entity.dto.Result;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MultipartException;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @title: DefaultGlobalExceptionHandlerAdvice.java
 * @description: 全局异常处理
 * @author: George
 * @date: 2023/8/7 15:48
 */
@Slf4j
public class DefaultGlobalExceptionHandlerAdvice {

    @ExceptionHandler(value = {IllegalArgumentException.class})
    public Object httpRequestMethodNotSupportedException(IllegalArgumentException ex) {
        log.error("IllegalArgumentException :{}", ex);
        ex.printStackTrace();
        return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID);
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public Object httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        log.error("httpRequestMethodNotSupportedException :{}", ex);
        return Result.fail(SystemErrorType.METHOD_NOT_ALLOWED);
    }

    @ExceptionHandler(value = {JSONException.class})
    public Object fastjsonException(JSONException ex) {
        log.error("fastjson exception:{}", ex);
        ex.printStackTrace();
        return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID);
    }

    @ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
    public Object methodArgumentTypeMismatchExceptionException(MethodArgumentTypeMismatchException ex) {
        log.error("Failed to convert request value exception:{}", ex);
        ex.printStackTrace();
        return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID);
    }

    @ExceptionHandler(value = {MissingServletRequestParameterException.class})
    public Object missingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.error("missing servlet request parameter exception:{}", ex);
        return Result.fail(SystemErrorType.ARGUMENT_NOT_VALID);
    }

    @ExceptionHandler(value = {MultipartException.class})
    public Object uploadFileLimitException(MultipartException ex) {
        log.error("upload file size limit:{}", ex);
        ex.printStackTrace();
        return Result.fail(SystemErrorType.UPLOAD_FILE_SIZE_LIMIT);
    }

    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public Result<Object> serviceException(MethodArgumentNotValidException ex) {
        List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
        String data = String.format("参数校验错误（%s）：%s", fieldErrors.size(),
                fieldErrors.stream()
                        .map(FieldError::getDefaultMessage)
                        .collect(Collectors.joining(";")));
        log.error("service exception:{}", data);
        ex.printStackTrace();
        return Result.fail(100003, data);
    }

    @ExceptionHandler(value = {BaseException.class})
    public Object baseException(BaseException ex) {
        log.error("base exception:{}", ex.getErrorType() == null ? ex.getMessage() : ex.getErrorType().getMsg());
        ex.printStackTrace();
        if (null == ex.getErrorType()) {
            return Result.fail(SystemErrorType.SYSTEM_ERROR.getCode(),ex.getMessage());
        } else {
            return Result.fail(ex.getErrorType());
        }
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object exception(Exception ex) {
        log.error("exception:{}", Throwables.getStackTraceAsString(ex));
        return Result.fail();
    }

}
